﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace Faust.Andrew.MTG
{
    /// <summary>
	/// Interaction logic for ImportWindow.xaml
	/// </summary>
	public partial class ImportWindow : Window
	{
        private Gatherer _gatherer;
        private DataStore _dataStore;
        private Importer _importer;

        private bool _isApprenticeFormat;
        private CardSearchParameters _lastSearchParameters;
        private CardSearchResults _lastSearchResults;

        private System.ComponentModel.BackgroundWorker _worker;

        private TreeViewItem _currentTreeItem;       

		public ImportWindow()
		{
			InitializeComponent();		
		}

        public ImportWindow(Gatherer gatherer, DataStore dataStore)
            : this()
        {
            if (gatherer == null)
                throw new ArgumentNullException("gatherer", "gatherer is null.");
            if (dataStore == null)
                throw new ArgumentNullException("dataStore", "dataStore is null.");

            //Need a new Gatherer object so that it won't fire the events on the original object
            _gatherer = gatherer.Clone();
            _gatherer.FindCardsCompleteEvent += new FindCardsCompleteHandler(_gatherer_FindCardsCompleteEvent);
            _dataStore = dataStore;

            //Need to create a clone for the importer to keep the event processing separated.
            _importer = new Importer(_gatherer.Clone(), _dataStore);
            _importer.ProgessEvent += _importer_ProgessEvent;
        }

        void _importer_ProgessEvent(object sender, ImporterProgressEventArgs e)
        {
            _worker.ReportProgress(1, e.CardName);
        }

        private void ButtonSave_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            //Check to see if all the invalid matches have been cleaned up. If not give a warning and an opportunity for 
            //the user to correct it.
            int unmatchedCount = _importer.Matches.Count(match => match.MatchState != MatchStates.Match);
            if (unmatchedCount > 0)
            {
                if (MessageBox.Show(String.Format("There are {0} cards. If you proceed they will not be imported. Do you wish to proceed?", unmatchedCount), 
                        "Unmatched Cards Exist", 
                        MessageBoxButton.YesNo) == MessageBoxResult.No)
                {
                    return;
                }
            }

            
            //If the user is creating a deck we need to ensure that the name has been set.
            if (chkCreateDeck.IsChecked.Value)
            {
                if (String.IsNullOrEmpty(txtDeckName.Text.Trim()))
                {
                    MessageBox.Show("Must Set a Deck Name");
                    return;
                }
            }

            //Write the cards and the ownership to the database.
            _importer.SaveCards(chkUpdateOwned.IsChecked.Value);

            //Now create the actual deck. The cards already exist so it's just a matter of creating the links.
            if (chkCreateDeck.IsChecked.Value)
            {
                _importer.CreateDeck(txtDeckName.Text, txtDeckDescription.Text);
            }
            
            //Success so we can close the window
            Hide();
        }

        private void ButtonCancel_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Hide();
        }

        private void ButtonBrowse_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
            ofd.FileName = FileTextBox.Text;
            ofd.DefaultExt = ".txt";
            ofd.Filter = "Text Files (.txt)|*.txt|Apprentice Deck (*.dec)|*.dec|All Files (*.*)|*.*";

            if (ofd.ShowDialog() == true)
            {
                FileTextBox.Text = ofd.FileName;

                //If filter index 1 is selected it means the apprentice deck format
                //was selected so we'll need to use the Apprentice deck importer code.
                _isApprenticeFormat = ofd.FilterIndex == 2;
            }
        }

        private void ButtonPreview_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            if (!System.IO.File.Exists(FileTextBox.Text))
            {
                MessageBox.Show("File not found.");
                return;
            }

            ButtonPreview.IsEnabled = false;

            ProgressLabel.Content = String.Empty;
            ProcessingStatusBar.Visibility = Visibility.Visible;

            _worker = new System.ComponentModel.BackgroundWorker();
            _worker.WorkerReportsProgress = true;
            _worker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(_worker_ProgressChanged);
            _worker.DoWork += new System.ComponentModel.DoWorkEventHandler(_worker_DoWork);
            _worker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);            

            ImportParameters iParams = new ImportParameters 
            { 
                FileName = FileTextBox.Text, 
                IsApprenticeFormat = _isApprenticeFormat,
                SkipFirst = SkipFirstCheckBox.IsChecked.Value 
            };

            _worker.RunWorkerAsync(iParams);      
        }

        void _worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            _worker.Dispose();
            ProcessingStatusBar.Visibility = Visibility.Collapsed;

            LoadTree();

            ButtonPreview.IsEnabled = true;
        }

        void _worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            ImportParameters iParams = (ImportParameters) e.Argument;
            if (iParams.IsApprenticeFormat)
            {
                _importer.LoadApprenticeFile(iParams.FileName);
            }
            else
            {
                _importer.LoadFile(iParams.FileName, iParams.SkipFirst);
            }
        }

        void _worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            ProgressLabel.Content = e.UserState;
        }

        private void LoadTree()
        {
            TreeCards.ItemsSource = null;
            TreeCards.Items.Clear();

            //Create the root nodes. Set the success node to have the link to all the matched cards
            MatchSuccessTreeViewItem successNode = new MatchSuccessTreeViewItem(_importer.ExactMatchCards);
            successNode.Header = "Match";

            TreeViewItem multipleMatchNode = new TreeViewItem();
            multipleMatchNode.Header = "Multiple Matches";

            TreeViewItem noMatchNode = new TreeViewItem();
            noMatchNode.Header = "No Matches";

            TreeCards.Items.Add(successNode);
            TreeCards.Items.Add(multipleMatchNode);
            TreeCards.Items.Add(noMatchNode);

            //Loop through the matches and create the necessary match tree node
            foreach (CardMatch match in _importer.Matches)
            {
                if (match.MatchState == MatchStates.Multiple)
                {
                    MultipleMatchTreeViewItem item = new MultipleMatchTreeViewItem(match);
                    item.Header = GetTreeViewHeader(match.Name, false);
                    multipleMatchNode.Items.Add(item);
                }
                else if (match.MatchState == MatchStates.NoMatch)
                {
                    NoMatchTreeViewItem item = new NoMatchTreeViewItem(match);
                    item.Header = GetTreeViewHeader(match.Name, false);
                    noMatchNode.Items.Add(item);
                }
            }

            //Set the Success Node as the selected node so that it will load them in the preview window.
            SetSelectedNode(successNode);
        }

        private object GetTreeViewHeader(string headerText, bool isValid)
        {
            Label headerLabel = new Label();

            headerLabel.Content = headerText;
            Brush textBrush;

            if (isValid)
            {
                textBrush = new SolidColorBrush(Colors.Green);
            }
            else
            {
                textBrush = new SolidColorBrush(Colors.Red);
            }

            headerLabel.Foreground = textBrush;

            return headerLabel;
        }

        private void SetSelectedNode(TreeViewItem item)
        {
            if (item is MatchSuccessTreeViewItem)
            {
                SetSelectedNode((MatchSuccessTreeViewItem)item);
            }
            else if (item is MultipleMatchTreeViewItem)
            {
                MatchTreeViewItem matchItem = item as MatchTreeViewItem;
                if (matchItem.Match.MatchState == MatchStates.Match)
                {
                    SetSelectedNode(matchItem, matchItem.Match.ExactMatch);
                }
                else
                {
                    SetSelectedNode((MultipleMatchTreeViewItem)item);
                }
            }
            else if (item is NoMatchTreeViewItem)
            {
                MatchTreeViewItem matchItem = item as MatchTreeViewItem;
                if (matchItem.Match.MatchState == MatchStates.Match)
                {
                    SetSelectedNode(matchItem, matchItem.Match.ExactMatch);
                }
                else
                {
                    SetSelectedNode((NoMatchTreeViewItem)item);
                }
            }
        }

        private void ResetCardsListBox()
        {
            CardsListBox.ItemsSource = null;
            CardsListBox.Items.Clear();
            SearchPanel.Visibility = Visibility.Collapsed;
            SearchTextBox.Text = String.Empty;

            _lastSearchResults = null;
            _lastSearchParameters.Name = String.Empty;
            _lastSearchParameters.Page = 0;
            pageControl.SetPages(0, 0, true);

            _currentTreeItem = null;
        }

        private void SetSelectedNode(MatchTreeViewItem item, Card card)
        {
            ResetCardsListBox();
            _currentTreeItem = item;
            List<Card> cards = new List<Card>();
            cards.Add(card);

            CardsListBox.ItemsSource = cards;
        }

        private void SetSelectedNode(MatchSuccessTreeViewItem item)
        {
            ResetCardsListBox();
            _currentTreeItem = item;

            CardsListBox.ItemsSource = item.Cards;
        }

        private void SetSelectedNode(MultipleMatchTreeViewItem item)
        {
            ResetCardsListBox();
            _currentTreeItem = item;

            CardsListBox.ItemsSource = item.Match.PossibleMatches;
            SearchPanel.Visibility = Visibility.Visible;
        }

        private void SetSelectedNode(NoMatchTreeViewItem item)
        {
            ResetCardsListBox();
            _currentTreeItem = item;

            SearchPanel.Visibility = Visibility.Visible;
        }        

        private void TreeCards_SelectedItemChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<object> e)
        {
            if (TreeCards.SelectedItem is TreeViewItem)
            {
                SetSelectedNode((TreeViewItem)TreeCards.SelectedItem);
            }
        }

        private void MenuSetCard_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            if (_currentTreeItem is MatchSuccessTreeViewItem)
            {
                MessageBox.Show("Changing matches on exact match results not supported.");
                return;
            }

            if (CardsListBox.SelectedItem is Card && _currentTreeItem is MatchTreeViewItem)
            {
                Card card = CardsListBox.SelectedItem as Card;
                MatchTreeViewItem matchItem = _currentTreeItem as MatchTreeViewItem;

                if (matchItem.Match.MatchState == MatchStates.Match)
                {
                    MessageBox.Show("Match already exists. You must first clear the match if you wish to change it.");
                    return;
                }

                matchItem.Match.SetMatch(card);
                matchItem.Header = GetTreeViewHeader(card.Name, true);
            }
        }

        private void ClearMatchMenu_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            if (TreeCards.SelectedItem == null)
            {
                MessageBox.Show("You must first select an item from the tree before you can clear the match.");
                return;
            }

            if (TreeCards.SelectedItem is MatchSuccessTreeViewItem)
            {
                MessageBox.Show("Clearing matches on exact match results not supported");
                return;
            }

            if (TreeCards.SelectedItem is MatchTreeViewItem)
            {
                MatchTreeViewItem item = TreeCards.SelectedItem as MatchTreeViewItem;
                if (item is MultipleMatchTreeViewItem)
                {
                    item.Match.RejectMatch(MatchStates.Multiple);
                }
                else
                {
                    item.Match.RejectMatch(MatchStates.NoMatch);
                }

                item.Header = GetTreeViewHeader(item.Match.Name, false);
            }
        }

        private void Search()
        {
            if (SearchTextBox.Text.Length == 0)
            {
                MessageBox.Show("Must enter a card name");
                return;
            }
           
            CardSearchParameters searchParameters = new CardSearchParameters()
            {
                Name = SearchTextBox.Text,
                SortOrder = SortOrder.Name,
                Page = 0,
                UseGatherer = true
            };

            Search(searchParameters);            
        }

        private void Search(CardSearchParameters searchParameters)
        {
            ProgressLabel.Content = SearchTextBox.Text;
            ProcessingStatusBar.Visibility = Visibility.Visible;

            _lastSearchParameters = searchParameters;
            _gatherer.FindCardsAsync(searchParameters);
        }

        void _gatherer_FindCardsCompleteEvent(object sender, FindCardsEventArgs e)
        {
            CardsListBox.ItemsSource = e.Results.Cards;
            _lastSearchResults = e.Results;
            pageControl.SetPages(_lastSearchResults.Page, _lastSearchResults.Pages, true);
            
            ProcessingStatusBar.Visibility = Visibility.Collapsed;
        }

        private void SearchButton_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            Search();
        }

        private void SearchTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                Search();
            }
        }

        private void pageControl_PageChangedEvent(object sender, Faust.Andrew.MTG.PageChangedEventArgs e)
        {
            if (_lastSearchResults == null || String.IsNullOrEmpty(_lastSearchParameters.Name)) { return; }

            _lastSearchParameters.Page = e.Page;

            Search(_lastSearchParameters);
        }
	}
}